import model


class UmlVisitor:
    def visit(self, mod: model.UmlModel):
        self.model = mod
        self.definedTypes: dict[str, model.UmlElement] = {}
        self.__get_primitive_types()
        self.__accept_model(self.model)

    def __get_primitive_types(self):
        self.definedTypes[model.UmlXmiInfo.type_boolean] = "bool"
        self.definedTypes[model.UmlXmiInfo.type_integer] = "int"
        self.definedTypes[model.UmlXmiInfo.type_real] = "double"
        self.definedTypes[model.UmlXmiInfo.type_string] = "QString"
        self.definedTypes[model.UmlXmiInfo.type_unlimited] = "int"

    def __accept_model(self, mod: model.UmlModel) -> None:
        for package in mod.packages:
            self.__accept_package(package)
        for profile in mod.profiles:
            self.__accept_profile(profile)

    def __accept_package(self, package: model.UmlPackage) -> None:
        if package is None:
            return

        for element in package.packagedElements.values():
            if element.xmi_type == model.UmlXmiInfo.type_package:
                self.__accept_package(element)
            elif element.xmi_type == model.UmlXmiInfo.type_class:
                self.__accept_class(element)
            elif element.xmi_type == model.UmlXmiInfo.type_data_type:
                self.__accept_class(element)
            elif element.xmi_type == model.UmlXmiInfo.type_enumeration:
                self.__accept_enumeration(element)
            elif element.xmi_type == model.UmlXmiInfo.type_primitive_type:
                self.__accept_primitive_type(element)
            elif element.xmi_type == model.UmlXmiInfo.type_extension:
                self.__accept_extension(element)
            elif element.xmi_type == model.UmlXmiInfo.type_association:
                self.__accept_association(element)
            elif element.xmi_type == model.UmlXmiInfo.type_package_import:
                self.__accept_package_import(element)
            else:
                print(element.xmi_type, element.xmi_id)

    def __accept_profile(self, profile: model.UmlProfile) -> None:
        if profile is None:
            return

        for element in profile.packagedElements.values():
            if element.xmi_type == model.UmlXmiInfo.type_stereotype:
                self.__accept_package_import(element)
            elif element.xmi_type == model.UmlXmiInfo.type_extension:
                self.__accept_extension(element)
            else:
                print(element.xmi_type, element.xmi_id)

    def __accept_class(self, cls: model.UmlClass) -> None:
        for rule in cls.ownedRules:
            self.__accept_rule(rule)

        for general in cls.generalizations:
            self.__accept_general(general)

        for attr in cls.ownedAttributes:
            self.__accept_attr(attr)

        for op in cls.ownedOperations:
            self.__accept_op(op)

    def __accept_enumeration(self, item: model.UmlEnumeration) -> None:
        for literal in item.ownedLiterals:
            self.__accept_enum_literal(literal)

    def __accept_enum_literal(self, item: model.UmlEnumerationLiteral) -> None:
        pass

    def __accept_rule(self, item: model.UmlConstraint) -> None:
        pass

    def __accept_general(self, item: model.UmlGeneralization) -> None:
        pass

    def __accept_attr(self, attr: model.UmlProperty) -> None:
        if attr.lowerValue is not None and attr.upperValue is None:
            text = ""
            if attr.lowerValue is not None:
                text += f"lowerValue: {attr.lowerValue.value}, "
            else:
                text += "None: None, "
            if attr.upperValue is not None:
                text += f"upperValue: {attr.upperValue.value}"
            else:
                text += "None: None"
            print(f"{attr.xmi_id}, {attr.type.href}, {text}")

    def __accept_op(self, op: model.UmlOperation) -> None:
        for rule in op.ownedRules:
            self.__accept_rule(rule)

        for param in op.ownedParameters:
            self.__accept_param(param)

    def __accept_param(self, param: model.UmlParameter) -> None:
        # if param.lowerValue is not None or param.upperValue is not None:
        #     text = ""
        #     if param.lowerValue is not None:
        #         text += f"lowerValue: {param.lowerValue.value}, "
        #     else:
        #         text += "None: None, "
        #     if param.upperValue is not None:
        #         text += f"upperValue: {param.upperValue.value}"
        #     else:
        #         text += "None: None"
        #     print(f"{text}")
        pass

    def __accept_primitive_type(self, item: model.UmlPrimitiveType) -> None:
        pass

    def __accept_extension(self, item: model.UmlExtension) -> None:
        pass

    def __accept_association(self, item: model.UmlAssociation) -> None:
        pass

    def __accept_package_import(self, element: model.UmlPackageImport) -> None:
        pass
